package export;

import java.util.Map;

/**
 * Interface for objects supporting additional properties as a {@link Map} of (String, Object) entries.
 * 
 * @param <S>
 *            The real implementation of {@link AdditionalPropertyMapSupport}. This generic type is for chain-based
 *            methods.
 */
public interface AdditionalPropertyMapSupport<S extends AdditionalPropertyMapSupport<?>> {

    /**
     * Returns current additional properties as another {@link Map}.
     * 
     * @return A new {@link Map} containing all additional properties.
     */
    Map<String, Object> getAdditionalProperties();

    /**
     * Returns an additional property in given result type.
     * 
     * @param <T>
     * @param name
     * @param resultType
     * @return Property value or <code>null</code> if this request has no property with given name.
     * @throws ClassCastException
     *             If result property cannot be casted to given result type.
     */
    <T> T getAdditionalProperty(String name, Class<T> resultType) throws ClassCastException;

    /**
     * Returns an additional property strictly in given result type. The 'strict' here means the property value must NOT
     * be <code>null</code> and must match exactly the result type.
     * 
     * @param <T>
     * @param name
     * @param resultType
     * @return Property value.
     */
    <T> T getAdditionalPropertyStrict(String name, Class<T> resultType);

    /**
     * Sets all additional properties required by given action command.
     * 
     * @param propertyMap
     *            All properties as a {@link Map}. Notice that this map is copied to current context's properties.
     * @return Current instance.
     */
    S withAdditionalProperties(Map<String, Object> propertyMap);

    /**
     * Sets an additional property required by current action command.
     * 
     * @param property
     * @param value
     * @return Current instance.
     */
    S withAdditionalProperty(String property, Object value);
}
